package Railroad;

import Railroad.Components.Rail;
import Railroad.Components.Signal;
import Railroad.Components.Switch;
import Railroad.Components.SwitchStatus;
import Railroad.Components.TrackNode;
import Railroad.GUI.RiadenieNavestidiel;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class Track {
    private final List<TrackNode> rails = new ArrayList<>(); // List traťových zariadení, ktoré sú potrebné pre stavbu cesty.
    private Signal startingSignal; // Návestidlo, ktorým začína daná cesta.
    private final boolean frameshift; // Typ cesty. 0 = normálna, 1 = posunová.
    private final HashMap<Switch, SwitchStatus> predstavenia = new HashMap<>();
    private final int id;
    private int nextNode;       // ktora cast trate je dalsia v poradi pri prechadzani vlaku (postupny rozpad cesty)
    private int nasledujuca;
    private int predchadzajuca;
    private boolean nudzova=false;
    private int maxRychlost;       
    private StavVytvoreniaCesty stav = StavVytvoreniaCesty.nevytvorena;
    
    // Konštruktor cesty.
    public Track(int id, boolean frameshift) { 
        this.id = id;
        this.frameshift = frameshift;
        nasledujuca=-1;
    }
    
    // Metóda, ktorá slúži na pridanie traťového zariadenia.
    public void addItem(TrackNode item) {
        if(item instanceof Switch)
        {
        Switch s=(Switch)item;
        maxRychlost=s.getMaxRychlost();
        }
        rails.add(item);
    }
    public int dajMaxRychlost()
    {
        return maxRychlost;
    }
    public int getId() {
        return id;
    }
    public List<TrackNode> getListOfNodes()
    {
        return rails;
    }

    public int getNasledujuca() {
        return nasledujuca;
    }

    public boolean isNudzova() {
        return nudzova;
    }

    public void setNudzova(boolean nudzova) {
        this.nudzova = nudzova;
    }
    
    public void setNasledujuca(int nasledujuca) {
        this.nasledujuca = nasledujuca;
    }

    public int getPredchadzajuca() {
        return predchadzajuca;
    }

    public void setPredchadzajuca(int predchadzajuca) {
        this.predchadzajuca = predchadzajuca;
    }
    
    public Color getColor()
    {
        switch (dajStav()) {
            case nevytvorena:
            case faza1:
            case prepinanieVyhybiek:
            case faza3:        
                return TrackNode.defaultColor;
            case fazaBiela:
                return new Color(255, 255, 255);
            default:
                if (frameshift) {
                    return Color.WHITE;
                } else {
                    return Color.GREEN;
                }
        }
    }
    public boolean jePosunova()
    {
        return frameshift;
    }
    // Metóda na nastavenie štartovacieho návestidla.
    public void setStartingSignal(Signal startSignal) {
        this.startingSignal = startSignal;
    }
    
    public void pridajNastavenie(Switch vyhybka, SwitchStatus smer){
        predstavenia.put(vyhybka, smer);
    }
    
    public Signal dajStartovacieNavestidlo() {
        return startingSignal;
    }
    // Metóda, ktorá obsadí všetky prvky potrebné na skladbu cesty a prestaví výhybky.
    public void obsadCestu(RiadenieNavestidiel r) {
        for (int i = 0; i < rails.size(); i++) 
             rails.get(i).setCurrentTrack(this);
        
        nextNode = 0;
        stav = StavVytvoreniaCesty.faza1;
        new Thread(new VytvaracCesty(this,r)).start();
    }
    
    public void nastavVyhybky() {
        for (Map.Entry<Switch, SwitchStatus> entry : predstavenia.entrySet()) {
            Switch sw = entry.getKey();
            SwitchStatus targetStatus = entry.getValue();
            if (entry.getKey().getStatus() != targetStatus) {
                sw.ziadostNaPrestavenie(targetStatus);
                sw.prestav(SwitchStatus.UNKNOWN);
            }
        }
    }
    
    public boolean maNastaveneVyhybky() {
        for (Map.Entry<Switch, SwitchStatus> entry : predstavenia.entrySet()) {
            Switch sw = entry.getKey();
            SwitchStatus status = sw.getStatus();
            SwitchStatus targetStatus = entry.getValue();
            if (status != targetStatus)
                return false;
        }
        return true;
    }
    
    public void zrusCestu() {
        for (int i = 0; i < rails.size(); i++)
            rails.get(i).setCurrentTrack(null);
        stav = StavVytvoreniaCesty.nevytvorena;
    }
    
    public boolean jeVytvorena() {
        return dajStav() == StavVytvoreniaCesty.vytvorena;
    }
    
    public boolean jeRusena() {
        return dajStav() == StavVytvoreniaCesty.rusena;
    }
    
    public StavVytvoreniaCesty dajStav() {
        return stav;
    }
    
    public void zmenStav(StavVytvoreniaCesty stav) {
        this.stav = stav;
    }
    
    // vrati poslednu kolaj trate
    private Rail getLastRail() {
        TrackNode node = rails.get(rails.size() - 1);
        return (Rail) node;
    }
    
    public boolean skontrolujKlik(int x,int y) {
        Rail lastRail = getLastRail();
        return lastRail.isOnXY(x, y);
    }
    
    // vrati true ak nie je nic obsadene ani pouzite na cestu
    public boolean volna() {
        if (dajStav() != StavVytvoreniaCesty.nevytvorena)
            return false;
        
        for (TrackNode node : rails) {
            if (node.getBusy() || node.isOnTrack())
                return false;
        }
        
        return true;
    }
    
    // aspon prva cast cesty uz bola obsadena
    public boolean jePouzita() {
        return nextNode > 0;
    }

    /**
     * oddeli dalsiu cast z cesty ak je obsadena (pri prechode vlaku sa cesta rusi)
     * @return true ak bola posledna cast trate uvolnena z trate po obsadeni
     */
    public boolean kontrolaRozpadu() {
        while (nextNode < rails.size()) {
            TrackNode node = rails.get(nextNode);
            if (!node.getBusy())
                return false;
            node.setCurrentTrack(null);
            nextNode++;
            
            if (nextNode == 1)
                dajStartovacieNavestidlo().setColor(Signal.defaultColor);
        }
        stav = StavVytvoreniaCesty.nevytvorena;
        return true;
    }
}